#ifndef __case_uhf_kenny_kfjiweiiur89u83r33e3e__
#define __case_uhf_kenny_kfjiweiiur89u83r33e3e__

#include <hude/base/log.hpp>
#include <hude/aio/context.hpp>

#include "test/test.hpp"

#include "brick/brick.hpp"
#include "plugs/virt-x2000/uhf/packet.hpp"

namespace test
{
    using namespace ha;
    using namespace pgl::x2000;

    //--------------------------------------------------------------------------------
    struct case_uhf_t : public hude::test::case_t
    {
        enum { emLAST = 3 , emCOUNT };

        hude::aio::aio_t<> aio_;
        bool               ret_;

        // 测试过程
        bool run() override;

        bool start();
        void stop();
    };

    //--------------------------------------------------------------------------------
    inline bool case_uhf_t::run()
    {
        aio_ = hude::aio::context_t<>::aio();

        auto ret = aio_->run( [ = ]() {
            std::thread{ [=] () { ret_ = start(); stop(); } }.detach();
        } );

        return ret == 0 && ret_;
    }

    //--------------------------------------------------------------------------------
    inline void case_uhf_t::stop()
    {
        std::thread{ [ = ] {
            std::this_thread::sleep_for( std::chrono::milliseconds( 1000U ) );
            this->aio_->cancel();
        } }.detach();
    }

    //--------------------------------------------------------------------------------
    inline bool case_uhf_t::start()
    {
        factory_brick_t::plug_t plug{ "./build-debug/lib/libvirt-x2000.so" };

        if( ! plug )
        {
            log_err( "ERROR: load plug: uhf" );
            return false;
        } else {
            log_inf( "SUCCESS: load factory( uhf )" );
        }

        auto cfg = hude::utils::json_t::parse(
            R"({
                "rfid": [
                    { "ant": 255, "rand": 100, "ch": 3, "id": "FFFFFFAAFFAAFFFF" }
                ]
            })" );

        auto uhf = plug( hude::aio::context_t<>::aio(), cfg );

        if( ! uhf )
        {
            log_err( "ERROR: production uhf instance." );
            return false;
        }

        int reqs =  0;
        int reps =  0;

        uhf->cb_recv( [&]( const hude::buffer_t& buffer ) {
            if( buffer.empty() )
            {
                if( reps < emLAST ) log_war( "\t recv index( %d ) empty buffer{}" );
            } else {
                log_nte( "\t recv <<< index( %d ) buffer{ %s }", reps, hude::utils::to_hex( buffer ).c_str() );
            }
            reps += 1;
        } );

        std::list< std::tuple< int, hude::buffer_t > > buffers;

        {
            packet_req_t< _token_t< 0x00, 0x02, pgl::x2000::mid_t::emSTOP > > req{};
            buffers.emplace_back( 1, req.to_buffer() );
        }

        {
            packet_req_t< _token_t< 0x00, 0x02, pgl::x2000::mid_t::emSET_POWER > > req{ false };
            buffers.emplace_back( 1, req.to_buffer() );
        }

        {
            static const pgl::x2000::argument_t< uint8_t > ps[] = {  { 1U, 30U }, { 2U, 30U }, { 3U, 30U } };
            packet_req_t< _token_t< 0x00, 0x02, pgl::x2000::mid_t::emSET_POWER > > req{ ps, 3U };
            buffers.emplace_back( 1, req.to_buffer() );
        }

        {
            static const pgl::x2000::argument_t< uint8_t > ps[] = {  { 1U, 0xffU }, { 2U, 30U }, { 3U, 30U } };
            packet_req_t< _token_t< 0x00, 0x02, pgl::x2000::mid_t::emSET_POWER > > req{ ps, 3U };
            buffers.emplace_back( 1, req.to_buffer() );
        }

        {
            packet_req_t< _token_t< 0x00, 0x02, pgl::x2000::mid_t::emSET_RF_FREQ > > req{};
            buffers.emplace_back( 1, req.to_buffer() );
        }

        {
            static const uint8_t fs[] = { 1, 2, 3, 4, 5 };
            packet_req_t< _token_t< 0x00, 0x02, pgl::x2000::mid_t::emSET_RF_FREQ > > req{ fs, 5U };
            buffers.emplace_back( 1, req.to_buffer() );
        }

        {
            static const uint8_t fs[] = { 0xff, 2, 3, 4, 5 };
            packet_req_t< _token_t< 0x00, 0x02, pgl::x2000::mid_t::emSET_RF_FREQ > > req{ fs, 5U };
            buffers.emplace_back( 1, req.to_buffer() );
        }

        {
            packet_req_t< _token_t< 0x00, 0x02, pgl::x2000::mid_t::emSET_RF_BAND > > req{ 3U };
            buffers.emplace_back( 1, req.to_buffer() );
        }

        {
            packet_req_t< _token_t< 0x00, 0x02, pgl::x2000::mid_t::emSET_RF_BAND > > req{ 0xff };
            buffers.emplace_back( 1, req.to_buffer() );
        }

        {
            packet_req_t< _token_t< 0x00, 0x02, pgl::x2000::mid_t::emSET_TAG > > req{ 0U, 0U };
            buffers.emplace_back( 1, req.to_buffer() );
        }

        {
            packet_req_t< _token_t< 0x00, 0x02, pgl::x2000::mid_t::emSET_EPC > > req{ 3U, 1U, 2U, 0 };
            buffers.emplace_back( 1, req.to_buffer() );
        }

        {
            packet_req_t< _token_t< 0x00, 0x02, pgl::x2000::mid_t::emSET_EPC > > req{ 3U, 1U, 2U, 0xff };
            buffers.emplace_back( 1, req.to_buffer() );
        }

        for( const auto& item : buffers )
        {
            int step = std::get<0>( item );
            const auto& buffer = std::get<1>( item );

            for( int i = 0; i < emCOUNT; ++i )
            {
                log_inf( "\t send >>> index( %d ) buffer{ %s }", reqs, hude::utils::to_hex( buffer ).c_str() );

                uhf->send( &(buffer[0]), buffer.size() );

                reqs += step;
            }
        }

        {
            auto buffer = pkt_req_t< pgl::x2000::mid_t::emREAD >::type_t{ 1U, true, true, false }.to_buffer();
            
            log_inf( "\t send >>> index( %d ) buffer{ %s }", reqs, hude::utils::to_hex( buffer ).c_str() );

            uhf->send( &(buffer[0]), buffer.size() );
        }

        std::this_thread::sleep_for( std::chrono::milliseconds( 1U ) );

        {
            auto buffer = pkt_req_t< pgl::x2000::mid_t::emSET_POWER >::type_t{ false }.to_buffer();
            
            log_inf( "\t send >>> index( %d ) buffer{ %s }", reqs, hude::utils::to_hex( buffer ).c_str() );

            uhf->send( &(buffer[0]), buffer.size() );
        }

        std::this_thread::sleep_for( std::chrono::milliseconds( 1U ) );

        {
            auto buffer = pkt_req_t< pgl::x2000::mid_t::emSTOP >::type_t{}.to_buffer();
            
            log_inf( "\t send >>> index( %d ) buffer{ %s }", reqs, hude::utils::to_hex( buffer ).c_str() );

            uhf->send( &(buffer[0]), buffer.size() );
        }

        std::this_thread::sleep_for( std::chrono::milliseconds( 500U ) );

        if( reqs > reps )
        {
            log_err( "test result failed: reqs( %d ) != reps( %d )", reqs, reps );
        }

        return reqs <= reps;
    }

    TEST_CASE_ADD( "case-uhf", case_uhf_t, false );

} // namespace test

#endif // __case_uhf_kenny_kfjiweiiur89u83r33e3e__


